﻿// -----------------------------------------------------------------------
// <copyright file="Program.cs" company="none">
// Copyright (c) 2012 M. Alberti, xanatos(at)live.it
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// </copyright>
// -----------------------------------------------------------------------

namespace FluentSerializer.Sample
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using FluentSerializer;
    using FluentSerializer.CollectionsHelpers;
    using FluentSerializer.Generators;
    using FluentSerializer.Utilities;

    /// <summary>
    /// 
    /// </summary>
    public class Program
    {
        /// <summary>
        /// 
        /// </summary>
        public static readonly Serializer<EmptyParameters> MySerializer = new Serializer<EmptyParameters>(); // typeof(VariableLengthInt32<>));

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args)
        {
            // The serializers that will be used for strings. 
            // The first two will prepend the length of the string in encoded bytes
            FluentSerializer.Serializer.UniversalSerializers[typeof(MyUtf8VariableLengthInt32String)] = StringGenerator.WithByteLengthBuildSerializer(null, null, typeof(string), typeof(VariableLengthInt32<>), () => Encoding.UTF8);
            FluentSerializer.Serializer.UniversalSerializers[typeof(MyAsciiVariableLengthInt32String)] = StringGenerator.WithByteLengthBuildSerializer(null, null, typeof(string), typeof(VariableLengthInt32<>), () => Encoding.ASCII);

            // The third one will prepend the length of the string in characters.
            // Clearly this one can't be used for UTF8 strings (that can have variable
            // length characters)
            // We are even selecting this serializer only in the "local" serializers,
            // serializers that are used only on this instance of the FluentSerializer.
            MySerializer.LocalSerializers[typeof(MyUnicodeVariableLengthInt32String)] = StringGenerator.WithCharLengthBuildSerializer(null, null, typeof(string), typeof(VariableLengthInt32<>), () => Encoding.Unicode);

            // You can force the compilation of the serializers you need.
            // You don't need to do it unless you want to check the serializers are correct.
            MySerializer.PreCompile(typeof(MyClass));
            MySerializer.PreCompile(typeof(MySimpleClass));
            MySerializer.PreCompile(typeof(MySimpleStruct));
            MySerializer.PreCompile(typeof(MySimpleClassDisposable));
            MySerializer.PreCompile(typeof(MySimpleStructDisposable));

            // This is a little helper that generates the various serializers in many small dll files.
            // Each file has this format: FS_TypeName.dll where TypeName is the type used as the key
            // of UniversalSerializers/LocalSerializers. Dump dumps both these dictionaries.
            MySerializer.Dump();

            // Note that you could do something like
            ////FluentSerializer.Serializer.UniversalSerializers[typeof(string)] = StringGenerator.WithByteLengthBuildSerializer(null, null, typeof(string), typeof(VariableLengthInt32<>), Encoding.UTF8);
            // and handle all the strings that don't have a serialization specifier as Int32 + UTF8

            // In the same way there are generators for collections (and other generic
            // types, like Tuple(s), Nullable values, Optional objects...), and they are present 
            // both in the FluentSerializer.Generators and in the instance of FluentSerializer,
            // Serializer.LocalGenerators.
            var obj1 = new MyClass(10)
            {
                Int1 = int.MaxValue,

                Version = 0,
                Bool1 = true,
                Int2 = 1,
                Int3 = 2,
                Short1 = 3,
                Tuple1 = Tuple.Create(1, Tuple.Create<short, bool>(2, true)),
                Ints1 = new[] { 1, 2, 3, 4 },
                Ints2 = new[] { 5, 6 },
                Ints3 = new int[] { },
                NullableInt1 = null,
                NullableInt2 = 5,
                OptionalInts1 = null,
                OptionalInts2 = new int[] { 8, 9 },
                OptionalList1 = null,
                OptionalList2 = new List<int> { 8, 9 },
                DateTime1 = new DateTime(2012, 8, 20, 14, 17, 30, DateTimeKind.Local),
                DateTime2 = new DateTime(2012, 8, 20, 14, 17, 30, DateTimeKind.Utc),
                Float1 = 1.15F,
                Double1 = 1.15D,
                Decimal1 = 1.15M,
                TimeSpan1 = TimeSpan.FromHours(1.5),
                String1 = "FluentSerializer",
                String2 = "is an incredible",
                String3 = "piece of software",
            };

            var obj2 = new MyClass(0);

            obj1.Version = 0;
            var serializedSizeVersion0 = MySerializer.Size(obj1, default(EmptyParameters));

            obj1.Version = 1;
            var serializedSizeVersion1 = MySerializer.Size(obj1, default(EmptyParameters));

            Array.Clear(MyClass.StaticReadonlyInts1, 0, MyClass.StaticReadonlyInts1.Length);
            Array.Clear(obj2.ReadonlyInts1, 0, obj2.ReadonlyInts1.Length);
            obj2.ReadonlyList1.Clear();

            using (var mb = new MemoryBuffer())
            {
                // You can use standard streams (even MemoryStream), but the serializer is a little
                // faster if you use its classes (MemoryBuffer + BinaryReaderStream/BinaryWriterStream)
                using (var bw = new BinaryWriterStream(mb))
                {
                    MySerializer.Serialize(bw, obj1, default(EmptyParameters));
                }

                using (var br = new BinaryReaderStream(mb))
                {
                    // If obj2 was a value type then you would have used this syntax:
                    MySerializer.Deserialize(br, obj2, default(EmptyParameters));

                    // If obj2 was a value type then you would have used this syntax:
                    ////obj2 = Serializer.Deserialize(br, obj2, default(EmptyParameters));
                    // or
                    ////obj2 = Serializer.Deserialize(br, default(MySubClass), default(EmptyParameters));
                    // depending if the deserialization needs a base object or not.
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static class MyUtf8VariableLengthInt32String
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public static class MyAsciiVariableLengthInt32String
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public static class MyUnicodeVariableLengthInt32String
        {
        }
    }
}
